package com.zg.system.auth;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zg.common.core.A;
import com.zg.common.core.C;
import com.zg.common.core.R;
import com.zg.common.core.dao.auth.AuthOrg;
import com.zg.common.core.dao.auth.AuthOrgDao;
import com.zg.system.auth.service.AuthOrgService;
import com.zg.system.auth.vo.DropOrgVo;
import com.zg.system.dao.SysOrgDao;
import com.zg.system.dao.entity.SysOrg;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

/**
 * @author Zxb
 */
@RestController
@RequiredArgsConstructor
public class OrgController {

    private final AuthOrgDao orgDao;
    private final AuthOrgService orgService;
    private final SysOrgDao sysOrgDao;

    @PostMapping("/org/root")
    @Transactional(rollbackFor = Exception.class)
    public R<?> initRoot() {
        String name = "组织架构";
        AuthOrg root = orgDao.getOne(new LambdaQueryWrapper<AuthOrg>()
                .isNull(AuthOrg::getPid));
        if (root != null) {
            return R.success(root);
        }
        root = new AuthOrg();
        root.setPid(null);
        root.setName(name);
        root.setLayer(1);
        root.setSort(1);
        orgDao.save(root);
        orgService.generateLink(root);
        return R.success(root);
    }

    @GetMapping("/org/next")
    public R<?> next(Long pid) {
        List<AuthOrg> list = orgDao.list(new LambdaQueryWrapper<AuthOrg>()
                .eq(AuthOrg::getPid, pid)
                .orderByAsc(AuthOrg::getSort));
        return R.success(list);
    }

    @PostMapping("/org/add")
    @Transactional(rollbackFor = Exception.class)
    public R<?> add(@RequestBody Long pid) {
        AuthOrg parent = orgDao.getById(pid);
        A.isInDatabase(parent, "上级组织");

        AuthOrg org = new AuthOrg();
        org.setPid(pid);
        org.setName(orgService.generateNewName(pid));
        org.setLayer(parent.getLayer() + 1);

        Integer sort = orgService.findMaxSort(pid);
        org.setSort(sort + 1);
        orgDao.save(org);
        orgService.generateLink(org);
        return R.success(org);
    }

    @PostMapping("/org/del")
    public R<?> del(@RequestBody Long id) {
        orgDao.removeById(id);
        return R.success();
    }

    @GetMapping("/org/info")
    public R<?> info(Long id) {
        AuthOrg org = orgDao.getById(id);
        return R.success(org);
    }

    @PostMapping("/org/update")
    @Transactional(rollbackFor = Exception.class)
    public R<?> update(@RequestBody AuthOrg org) {
        AuthOrg old = orgDao.getById(org.getId());
        A.isInDatabase(old, "当前组织");
        if (orgService.isNameConflict(org.getId(), org.getName())) {
            return R.error("组织名称冲突");
        }
        if (StrUtil.isNotBlank(org.getCode())
                && orgService.isCodeConflict(org.getId(), org.getCode())) {
            return R.error("组织编码冲突");
        }
        BeanUtil.copyProperties(org, old, C.IGNORED_PROPERTIES);
        orgDao.updateById(old);
        orgService.generateLink(old);
        return R.success(old);
    }

    @PostMapping("/org/drop")
    @Transactional(rollbackFor = Exception.class)
    public R<?> drop(@RequestBody DropOrgVo param) {
        Long dragId = param.getDragId();
        Long dropId = param.getDropId();
        Integer position = param.getPosition();

        AuthOrg dragObj = orgDao.getById(dragId);
        AuthOrg dropObj = orgDao.getById(dropId);
        if (position == 0) {
            orgService.moveInner(dragObj, dropObj);
        } else if (position > 0) {
            orgService.moveAfter(dragObj, dropObj);
        } else {
            orgService.moveBefore(dragObj, dropObj);
        }
        orgService.generateLink(dragObj);
        return R.success();
    }

    @PostMapping("/org/sort")
    public R<?> sort(@RequestBody List<String> sortList) {
        sortList.stream().forEach(t -> {
            String[] arr = t.split("_");
            Long id = Long.parseLong(arr[0]);
            Integer sort = Integer.parseInt(arr[1]);
            AuthOrg org = orgDao.getById(id);
            org.setSort(sort);
            orgDao.updateById(org);
        });
        return R.success();
    }

    @PostMapping("/org/migrate")
    @Transactional(rollbackFor = Exception.class)
    public R<?> migrate() {
        // 读取旧系统sys_org表数据，取到id和org_name，遍历存到新表auth_org表,将oldSystemOrgId落旧表id，levelOrgId落层级组织id，示例：一级组织001，二级组织则落001002，三级组织则落001002003，这个字段动态生成，别一样了即可
        
        // 获取或创建根组织
        R<?> rootResult = initRoot();
        AuthOrg rootOrg = (AuthOrg) rootResult.getData();
        
        // 获取旧系统所有组织数据
        List<SysOrg> sysOrgList = sysOrgDao.list();
        if (sysOrgList == null || sysOrgList.isEmpty()) {
            return R.success("旧系统无组织数据");
        }
        
        // 构建旧系统组织ID到新系统组织ID的映射，用于处理层级关系
        java.util.Map<Long, Long> oldToNewIdMap = new java.util.HashMap<>();
        java.util.Map<Long, AuthOrg> oldIdToAuthOrgMap = new java.util.HashMap<>();
        java.util.Map<Long, String> levelOrgIdMap = new java.util.HashMap<>();
        // 使用一个全局计数器，确保所有组织的编码全局唯一
        java.util.Set<String> usedCodes = new java.util.HashSet<>();
        java.util.concurrent.atomic.AtomicInteger globalCounter = new java.util.concurrent.atomic.AtomicInteger(1);
        
        // 第一次遍历，创建所有组织，并记录ID映射
        for (SysOrg sysOrg : sysOrgList) {
            // 先检查是否已经存在该组织（通过oldSystemOrgId判断）
            AuthOrg existingOrg = orgDao.getOne(new LambdaQueryWrapper<AuthOrg>()
                    .eq(AuthOrg::getOldSystemOrgId, sysOrg.getId()));
            
            if (existingOrg != null) {
                // 如果已存在，则记录映射关系，但不重复创建
                oldToNewIdMap.put(sysOrg.getId(), existingOrg.getId());
                oldIdToAuthOrgMap.put(sysOrg.getId(), existingOrg);
                levelOrgIdMap.put(sysOrg.getId(), existingOrg.getLevelOrgId());
                continue;
            }
            
            AuthOrg authOrg = new AuthOrg();
            authOrg.setName(sysOrg.getOrgName());
            authOrg.setCode(sysOrg.getOrgCode());
            if (sysOrg.getOrgNameShort() != null) {
                authOrg.setShortName(sysOrg.getOrgNameShort());
            }
            authOrg.setIntro(sysOrg.getOrgDesc());
            
            // 默认挂在根组织下，后面会根据层级关系调整
            authOrg.setPid(rootOrg.getId());
            authOrg.setLayer(rootOrg.getLayer() + 1);
            authOrg.setSort(orgService.findMaxSort(rootOrg.getId()) + 1);
            authOrg.setOldSystemOrgId(sysOrg.getId());
            
            // 先保存，获取到新ID
            orgDao.save(authOrg);
            
            // 记录映射关系
            oldToNewIdMap.put(sysOrg.getId(), authOrg.getId());
            oldIdToAuthOrgMap.put(sysOrg.getId(), authOrg);
        }
        
        // 第二次遍历，处理层级关系和levelOrgId
        for (SysOrg sysOrg : sysOrgList) {
            AuthOrg authOrg = oldIdToAuthOrgMap.get(sysOrg.getId());
            
            // 处理父子关系
            if (sysOrg.getOrgParid() != null && oldToNewIdMap.containsKey(sysOrg.getOrgParid())) {
                // 如果有父组织且父组织也在迁移范围内
                Long newParentId = oldToNewIdMap.get(sysOrg.getOrgParid());
                authOrg.setPid(newParentId);
                
                // 更新层级
                AuthOrg parentAuthOrg = oldIdToAuthOrgMap.get(sysOrg.getOrgParid());
                authOrg.setLayer(parentAuthOrg.getLayer() + 1);
                
                // 生成levelOrgId
                String parentLevelOrgId = parentAuthOrg.getLevelOrgId();
                if (parentLevelOrgId == null) {
                    parentLevelOrgId = "";
                }
                
                // 生成全局唯一的3位编码
                String codeStr;
                do {
                    codeStr = String.format("%03d", globalCounter.getAndIncrement());
                } while (usedCodes.contains(codeStr));
                usedCodes.add(codeStr);
                
                // 组合生成新的层级ID
                String newLevelOrgId = parentLevelOrgId + codeStr;
                levelOrgIdMap.put(sysOrg.getId(), newLevelOrgId);
                
                System.out.println("组织[" + sysOrg.getOrgName() + "] ID:" + sysOrg.getId() 
                    + " 父级levelOrgId:" + parentLevelOrgId 
                    + " 本级3位ID:" + codeStr 
                    + " 最终levelOrgId:" + newLevelOrgId);
                    
                authOrg.setLevelOrgId(newLevelOrgId);
            } else {
                // 如果没有父组织或父组织不在迁移范围内，直接挂在根组织下
                authOrg.setPid(rootOrg.getId());
                authOrg.setLayer(rootOrg.getLayer() + 1);
                
                // 生成levelOrgId
                String parentLevelOrgId = rootOrg.getLevelOrgId();
                if (parentLevelOrgId == null) {
                    parentLevelOrgId = "";
                }
                
                // 生成全局唯一的3位编码
                String codeStr;
                do {
                    codeStr = String.format("%03d", globalCounter.getAndIncrement());
                } while (usedCodes.contains(codeStr));
                usedCodes.add(codeStr);
                
                // 组合生成新的层级ID
                String newLevelOrgId = parentLevelOrgId + codeStr;
                levelOrgIdMap.put(sysOrg.getId(), newLevelOrgId);
                
                System.out.println("根节点下组织[" + sysOrg.getOrgName() + "] ID:" + sysOrg.getId() 
                    + " 父级levelOrgId:" + parentLevelOrgId 
                    + " 本级3位ID:" + codeStr 
                    + " 最终levelOrgId:" + newLevelOrgId);
                    
                authOrg.setLevelOrgId(newLevelOrgId);
            }
            
            // 更新组织
            orgDao.updateById(authOrg);
            
            // 生成链接关系
            orgService.generateLink(authOrg);
        }
        
        return R.success("组织数据迁移完成，共迁移 " + sysOrgList.size() + " 条数据");
    }
    
}
